<template>
  <div class="page_server_manage">

    <!-- 服务列表 -->
    <let-table v-if="serverList" :data="serverList" :title="$t('serverList.title.serverList')" :empty-msg="$t('common.nodata')" ref="serverListLoading">
      <let-table-column :title="$t('serverList.table.th.service')" prop="server_name"></let-table-column>
      <let-table-column :title="$t('serverList.table.th.ip')" prop="node_name" width="140px"></let-table-column>
      <let-table-column :title="$t('serverList.table.th.enableSet')">
        <template slot-scope="scope">
          <span v-if="!scope.row.enable_set">{{$t('common.disable')}}</span>
          <p v-else style="max-width: 200px">
            {{$t('common.set.setName')}}：{{scope.row.set_name}}<br>
            {{$t('common.set.setArea')}}：{{scope.row.set_area}}<br>
            {{$t('common.set.setGroup')}}：{{scope.row.set_group}}
          </p>
        </template>
      </let-table-column>
      <let-table-column :title="$t('serverList.table.th.configStatus')" width="90px">
        <template slot-scope="scope">
          <span :class="scope.row.setting_state === 'active' ? 'status-active' : 'status-off'"></span>
        </template>
      </let-table-column>
      <let-table-column :title="$t('serverList.table.th.currStatus')" width="65px">
        <template slot-scope="scope">
          <span :class="scope.row.present_state === 'active' ? 'status-active' : scope.row.present_state === 'activating' ? 'status-activating' : 'status-off'"></span>
        </template>
      </let-table-column>
      <let-table-column :title="$t('serverList.table.th.processID')" prop="process_id" width="80px"></let-table-column>
      <let-table-column :title="$t('serverList.table.th.version')" prop="patch_version" width="68px"></let-table-column>
      <let-table-column :title="$t('serverList.table.th.time')">
        <template slot-scope="scope">
          <span style="word-break: break-word">{{handleNoPublishedTime(scope.row.patch_time)}}</span>
        </template>
      </let-table-column>
      <let-table-column :title="$t('operate.operates')" width="260px">
        <template slot-scope="scope">
          <let-table-operation @click="configServer(scope.row.id)">{{$t('operate.update')}}</let-table-operation>
          <let-table-operation @click="openExpandModal(scope.row)" v-if="serverType === 'proxy' || serverType === 'router'">{{$t('dcache.expand')}}</let-table-operation>
          <let-table-operation @click="restartServer(scope.row.id)">{{$t('operate.restart')}}</let-table-operation>
          <let-table-operation class="danger" @click="stopServer(scope.row.id)">{{$t('operate.stop')}}</let-table-operation>
          <let-table-operation @click="manageServant(scope.row)">{{$t('operate.servant')}}</let-table-operation>
          <let-table-operation @click="showMoreCmd(scope.row)">{{$t('operate.more')}}</let-table-operation>
        </template>
      </let-table-column>
    </let-table>

    <!-- 服务实时状态 -->
    <let-table v-if="serverNotifyList && showOthers"
      :data="serverNotifyList" :title="$t('serverList.title.serverStatus')" :empty-msg="$t('common.nodata')" ref="serverNotifyListLoading">
      <let-table-column :title="$t('common.time')" prop="notifytime"></let-table-column>
      <let-table-column :title="$t('serverList.table.th.serviceID')" prop="server_id"></let-table-column>
      <let-table-column :title="$t('serverList.table.th.threadID')" prop="thread_id"></let-table-column>
      <let-table-column :title="$t('serverList.table.th.result')" prop="result"></let-table-column>
    </let-table>
    <let-pagination
      :page="pageNum" @change="gotoPage" style="margin-bottom: 32px;"
      :total="total">
    </let-pagination>

    <!-- 服务扩容弹窗 -->
    <let-modal
      v-model="expandModal.show"
      :title="$t('serviceExpand.title')"
      width="800px"
      :footShow="!!(expandModal.model && expandModal.model.server_name)"
      @on-confirm="expandService"
      @close="closeExpandModal"
      @on-cancel="closeExpandModal">
        <let-form
          v-if="!!(expandModal.model && expandModal.model.server_name)"
          ref="expandForm" itemWidth="360px" :columns="2" class="two-columns">
          <let-form-item :label="$t('common.service')">{{expandModal.model.server_name}}</let-form-item>
          <let-form-item :label="$t('common.ip')">{{expandModal.model.node_name}}</let-form-item>
          <let-form-item :label="$t('serviceExpand.form.tarIP')" itemWidth="100%" required>
            <let-input
              type="textarea"
              :rows="3"
              v-model="expandModal.expandIpStr"
              :placeholder="$t('serviceExpand.form.placeholder')"
              required
              :required-tip="$t('deployService.table.tips.empty')"
              >
            </let-input>
          </let-form-item>
          <let-form-item :label="$t('serviceExpand.form.nodeConfig')" itemWidth="100%">
            <let-checkbox
              v-model="expandModal.model.copy_node_config">
              {{$t('serviceExpand.form.copyNodeConfig')}}
            </let-checkbox>
          </let-form-item>
        </let-form>
    </let-modal>

    <!-- 编辑服务弹窗 -->
    <let-modal
      v-model="configModal.show"
      :title="$t('serverList.dlg.title.editService')"
      width="800px"
      :footShow="!!(configModal.model && configModal.model.server_name)"
      @on-confirm="saveConfig"
      @close="closeConfigModal"
      @on-cancel="closeConfigModal">
      <let-form
        v-if="!!(configModal.model && configModal.model.server_name)"
        ref="configForm" itemWidth="360px" :columns="2" class="two-columns">
        <let-form-item :label="$t('common.service')">{{configModal.model.server_name}}</let-form-item>
        <let-form-item :label="$t('common.ip')">{{configModal.model.node_name}}</let-form-item>
        <let-form-item :label="$t('serverList.dlg.isBackup')" required>
          <let-radio-group
            size="small"
            v-model="configModal.model.bak_flag"
            :data="[{ value: true, text: $t('common.yes') }, { value: false, text: $t('common.no') }]">
          </let-radio-group>
        </let-form-item>
        <let-form-item :label="$t('common.template')" required>
          <let-select
            size="small"
            v-model="configModal.model.template_name"
            v-if="configModal.model.templates && configModal.model.templates.length"
            required>
            <let-option v-for="t in configModal.model.templates" :key="t" :value="t">{{t}}</let-option>
          </let-select>
          <span v-else>{{configModal.model.template_name}}</span>
        </let-form-item>
        <let-form-item :label="$t('serverList.dlg.serviceType')" required>
          <let-select
            size="small"
            v-model="configModal.model.server_type"
            required>
            <let-option v-for="t in serverTypes" :key="t" :value="t">{{t}}</let-option>
          </let-select>
        </let-form-item>
        <let-form-item :label="$t('serverList.table.th.enableSet')" required>
          <let-radio-group
            size="small"
            v-model="configModal.model.enable_set"
            :data="[{ value: true, text: $t('common.enable') }, { value: false, text: $t('common.disable') }]">
          </let-radio-group>
        </let-form-item>
        <let-form-item :label="$t('common.set.setName')" required v-if="configModal.model.enable_set">
          <let-input
            size="small"
            v-model="configModal.model.set_name"
            :placeholder="$t('serverList.dlg.errMsg.setName')"
            required
            pattern="^[a-z]+$"
            :pattern-tip="$t('serverList.dlg.errMsg.setName')"
          ></let-input>
        </let-form-item>
        <let-form-item :label="$t('common.set.setArea')" required v-if="configModal.model.enable_set">
          <let-input
            size="small"
            v-model="configModal.model.set_area"
            :placeholder="$t('serverList.dlg.errMsg.setArea')"
            required
            pattern="^[a-z]+$"
            :pattern-tip="$t('serverList.dlg.errMsg.setArea')"
          ></let-input>
        </let-form-item>
        <let-form-item :label="$t('common.set.setGroup')" required v-if="configModal.model.enable_set">
          <let-input
            size="small"
            v-model="configModal.model.set_group"
            :placeholder="$t('serverList.dlg.errMsg.setGroup')"
            required
            pattern="^[0-9\*]+$"
            :pattern-tip="$t('serverList.dlg.errMsg.setGroup')"
          ></let-input>
        </let-form-item>

        <let-form-item :label="$t('serverList.dlg.asyncThread')" required>
          <let-input
            size="small"
            v-model="configModal.model.async_thread_num"
            :placeholder="$t('serverList.dlg.placeholder.thread')"
            required
            :pattern="configModal.model.server_type === 'tars_nodejs' ? '^[1-9][0-9]*$' : '^([3-9]|[1-9][0-9]+)$'"
            pattern-tip="$t('serverList.dlg.placeholder.thread')"
          ></let-input>
        </let-form-item>
        <let-form-item :label="$t('serverList.dlg.defaultPath')">
          <let-input
            size="small"
            v-model="configModal.model.base_path"
          ></let-input>
        </let-form-item>
        <let-form-item :label="$t('serverList.dlg.exePath')">
          <let-input
            size="small"
            v-model="configModal.model.exe_path"
          ></let-input>
        </let-form-item>
        <let-form-item :label="$t('serverList.dlg.startScript')">
          <let-input
            size="small"
            v-model="configModal.model.start_script_path"
          ></let-input>
        </let-form-item>
        <let-form-item :label="$t('serverList.dlg.stopScript')">
          <let-input
            size="small"
            v-model="configModal.model.stop_script_path"
          ></let-input>
        </let-form-item>
        <let-form-item :label="$t('serverList.dlg.monitorScript')" itemWidth="724px">
          <let-input
            size="small"
            v-model="configModal.model.monitor_script_path"
          ></let-input>
        </let-form-item>
        <let-form-item :label="$t('serverList.dlg.privateTemplate')" labelWidth="150px" itemWidth="724px">
          <let-input
            size="large"
            type="textarea"
            :rows="4"
            v-model="configModal.model.profile"
          ></let-input>
        </let-form-item>
      </let-form>
      <div v-else class="loading-placeholder" ref="configFormLoading"></div>
    </let-modal>

    <!-- Servant管理弹窗 -->
    <let-modal
      v-model="servantModal.show"
      :title="$t('serverList.table.servant.title')"
      width="1200px"
      :footShow="false"
      @close="closeServantModal">
      <let-button size="small" theme="primary" class="tbm16" @click="configServant()">{{$t('operate.add')}} Servant</let-button>
      <let-table v-if="servantModal.model" :data="servantModal.model" :empty-msg="$t('common.nodata')">
        <let-table-column :title="$t('operate.servant')" prop="servant"></let-table-column>
        <let-table-column :title="$t('serverList.table.servant.adress')" prop="endpoint"></let-table-column>
        <let-table-column :title="$t('serverList.table.servant.thread')" prop="thread_num"></let-table-column>
        <let-table-column :title="$t('serverList.table.servant.maxConnecttions')" prop="max_connections"></let-table-column>
        <let-table-column :title="$t('serverList.table.servant.maxQueue')" prop="queuecap"></let-table-column>
        <let-table-column :title="$t('serverList.table.servant.timeout')" prop="queuetimeout"></let-table-column>
        <let-table-column :title="$t('operate.operates')" width="90px">
          <template slot-scope="scope">
            <let-table-operation @click="configServant(scope.row.id)">{{$t('operate.update')}}</let-table-operation>
            <let-table-operation class="danger" @click="deleteServant(scope.row.id)">{{$t('operate.delete')}}</let-table-operation>
          </template>
        </let-table-column>
      </let-table>
      <div v-else class="loading-placeholder" ref="servantModalLoading"></div>
    </let-modal>

    <!-- Servant新增、编辑弹窗 -->
    <let-modal
      v-model="servantDetailModal.show"
      :title="servantDetailModal.isNew ? `${$t('operate.title.add')} Servant` : `${$t('operate.title.update')} Servant`"
      width="800px"
      :footShow="!!servantDetailModal.model"
      @on-confirm="saveServantDetail"
      @close="closeServantDetailModal"
      @on-cancel="closeServantDetailModal">
      <let-form
        v-if="servantDetailModal.model"
        ref="servantDetailForm" itemWidth="360px" :columns="2" class="two-columns">
        <let-form-item :label="$t('serverList.servant.appService')" itemWidth="724px">
          <span>{{servantDetailModal.model.application}}·{{servantDetailModal.model.server_name}}</span>
        </let-form-item>
        <let-form-item :label="$t('serverList.servant.objName')" required>
          <let-input
            size="small"
            v-model="servantDetailModal.model.obj_name"
            :placeholder="$t('serverList.servant.c')"
            required
            pattern="^[A-Za-z]+$"
            :pattern-tip="$t('serverList.servant.obj')"
          ></let-input>
        </let-form-item>
        <let-form-item :label="$t('serverList.servant.numOfThread')" required>
          <let-input
            size="small"
            v-model="servantDetailModal.model.thread_num"
            :placeholder="$t('serverList.servant.thread')"
            required
            pattern="^[1-9][0-9]*$"
            :pattern-tip="$t('serverList.servant.thread')"
          ></let-input>
        </let-form-item>
        <let-form-item :label="$t('serverList.table.servant.adress')" required itemWidth="724px">
          <let-input
            ref="endpoint"
            size="small"
            v-model="servantDetailModal.model.endpoint"
            placeholder="tcp -h 127.0.0.1 -t 60000 -p 12000"
            required
            :extraTip="isEndpointValid ? '' :
              $t('serverList.servant.error')"
          ></let-input>
        </let-form-item>
        <let-form-item :label="$t('serverList.servant.maxConnecttions')" labelWidth="150px">
          <let-input
            size="small"
            v-model="servantDetailModal.model.max_connections"
          ></let-input>
        </let-form-item>
        <let-form-item :label="$t('serverList.servant.lengthOfQueue')" labelWidth="150px">
          <let-input
            size="small"
            v-model="servantDetailModal.model.queuecap"
          ></let-input>
        </let-form-item>
        <let-form-item :label="$t('serverList.servant.queueTimeout')" labelWidth="150px">
          <let-input
            size="small"
            v-model="servantDetailModal.model.queuetimeout"
          ></let-input>
        </let-form-item>
        <let-form-item :label="$t('serverList.servant.allowIP')">
          <let-input
            size="small"
            v-model="servantDetailModal.model.allow_ip"
          ></let-input>
        </let-form-item>
        <let-form-item :label="$t('serverList.servant.protocol')" required>
          <let-radio-group
            size="small"
            v-model="servantDetailModal.model.protocol"
            :data="[{ value: 'tars', text: 'TARS' }, { value: 'not_tars', text: $t('serverList.servant.notTARS') }]">
          </let-radio-group>
        </let-form-item>
        <let-form-item :label="$t('serverList.servant.treatmentGroup')" labelWidth="150px">
          <let-input
            size="small"
            v-model="servantDetailModal.model.handlegroup"
          ></let-input>
        </let-form-item>
      </let-form>
    </let-modal>

    <!-- 更多命令弹窗 -->
    <let-modal
      v-model="moreCmdModal.show"
      :title="$t('operate.title.more')"
      width="700px"
      class="more-cmd"
      @on-confirm="invokeMoreCmd"
      @close="closeMoreCmdModal"
      @on-cancel="closeMoreCmdModal">
      <let-form v-if="moreCmdModal.model" ref="moreCmdForm">
        <let-form-item itemWidth="100%">
          <let-radio v-model="moreCmdModal.model.selected" label="setloglevel">{{$t('serverList.servant.logLevel')}}</let-radio>
          <let-select
            size="small"
            :disabled="moreCmdModal.model.selected !== 'setloglevel'"
            v-model="moreCmdModal.model.setloglevel">
            <let-option v-for="l in logLevels" :key="l" :value="l">{{l}}</let-option>
          </let-select>
        </let-form-item>
        <let-form-item itemWidth="100%">
          <let-radio v-model="moreCmdModal.model.selected" label="loadconfig">{{$t('serverList.servant.pushFile')}}</let-radio>
          <let-select
            size="small"
            :placeholder="moreCmdModal.model.configs && moreCmdModal.model.configs.length ? $t('pub.dlg.defaultValue') : $t('pub.dlg.noConfFile')"
            :disabled="!(moreCmdModal.model.configs && moreCmdModal.model.configs.length)
              || moreCmdModal.model.selected !== 'loadconfig'"
            v-model="moreCmdModal.model.loadconfig"
            :required="moreCmdModal.model.selected === 'loadconfig'">
            <let-option v-for="l in moreCmdModal.model.configs" :key="l.filename" :value="l.filename">{{l.filename}}</let-option>
          </let-select>
        </let-form-item>
        <let-form-item itemWidth="100%">
          <let-radio v-model="moreCmdModal.model.selected" label="command">{{$t('serverList.servant.sendCommand')}}</let-radio>
          <let-input
            size="small"
            :disabled="moreCmdModal.model.selected !== 'command'"
            v-model="moreCmdModal.model.command"
            :required="moreCmdModal.model.selected === 'command'"
          ></let-input>
        </let-form-item>
        <let-form-item itemWidth="100%">
          <let-radio v-model="moreCmdModal.model.selected" label="connection">{{$t('serverList.servant.serviceLink')}}</let-radio>
        </let-form-item>
        <let-form-item itemWidth="100%" v-if="serverType !== 'dcache'">
          <let-radio v-model="moreCmdModal.model.selected" label="undeploy_tars" class="danger">{{$t('operate.undeploy')}} {{$t('common.service')}}</let-radio>
        </let-form-item>
      </let-form>
    </let-modal>
  </div>
</template>

<script>
  import { expandServerPreview, autoPort, expandServer, addTask } from '@/dcache/interface.js'
const getInitialExpandModel = () => ({
  application: 'DCache',
  server_name: '',
  set: '',
  node_name: '',
  expand_nodes: [],
  enable_set: false,
  set_name: '',
  set_area: '',
  set_group: '',
  copy_node_config: false,
});
export default {
  name: 'ServerManage',
  data() {
    return {
      // 当前页面信息
      serverType: this.$route.params.serverType || 'tars',
      serverData: {
        level: 5,
        application: '',
        server_name: '',
        set_name: '',
        set_area: '',
        set_group: '',
      },

      // 服务列表
      serverList: [],

      // 操作历史列表
      serverNotifyList: [],
      pageNum: 1,
      pageSize: 20,
      total:1,

      // 编辑服务
      serverTypes: [
        'tars_cpp',
        'tars_java',
        'tars_php',
        'tars_nodejs',
        'not_tars',
        'tars_go'
      ],
      configModal: {
        show: false,
        model: null,
      },

      // 编辑servant
      servantModal: {
        show: false,
        model: null,
        currentServer: null,
      },
      servantDetailModal: {
        show: false,
        isNew: true,
        model: null,
      },

      // 更多命令
      logLevels: [
        'NONE',
        'DEBUG',
        'INFO',
        'WARN',
        'ERROR',
      ],
      moreCmdModal: {
        show: false,
        model: null,
        currentServer: null,
      },

      // 服务扩容
      expandModal: {
        show: false,
        model: getInitialExpandModel(),
        expandIpStr: ''
      },

      // 失败重试次数
      failCount :0
    };
  },
  computed: {
    showOthers() {
      return this.serverData.level === 5;
    },
    isEndpointValid() {
      if (!this.servantDetailModal.model || !this.servantDetailModal.model.endpoint) {
        return false;
      }
      return this.checkServantEndpoint(this.servantDetailModal.model.endpoint);
    },
  },
  watch: {
    '$route' (to, from) {
      this.getServerList();
      this.getServerNotifyList(1);
    },
  },
  methods: {
    // 获取服务列表
    getServerList() {
      const loading = this.$refs.serverListLoading.$loading.show();

      this.$ajax.getJSON('/server/api/server_list', {
        tree_node_id: this.$route.params.treeid,
      }).then(async (data) => {
        loading.hide();
        this.serverList = data;


        //在模块服务节点列表，如果该服务没有节点了， 在目录树去掉该服务；
        if (this.serverType === 'dcache') {
          let serverLength = this.serverList.length;
          if (serverLength > 0) return false;
          try {
            await this.$ajax.postJSON('/server/api/cache/removeServer', {server_name: this.$route.params.treeid.split('.')[1].substr(1)});
            this.$parent.getTreeData();
          } catch (err) {
            console.error(err)
          }

        } else if (this.serverType === 'proxy') {

          //在proxy服务节点列表，如果该服务没有节点了， 在目录树去掉该服务；
          let serverLength = this.serverList.length;
          if (serverLength > 0) return false;
          try {
            await this.$ajax.postJSON('/server/api/cache/removeProxy', {server_name: this.$route.params.treeid.split('.')[1].substr(1)});
            this.$parent.getTreeData();
          } catch (err) {
            console.error(err)
          }
        } else if (this.serverType === 'router') {

          //在proxy服务节点列表，如果该服务没有节点了， 在目录树去掉该服务；
          let serverLength = this.serverList.length;
          if (serverLength > 0) return false;
          try {
            await this.$ajax.postJSON('/server/api/cache/removeRouter', {server_name: this.$route.params.treeid.split('.')[1].substr(1)});
            this.$parent.getTreeData();
          } catch (err) {
            console.error(err)
          }
        }

      }).catch((err) => {
        loading.hide();
        this.$confirm(err.err_msg || err.message || this.$t('serverList.msg.fail'), this.$t('common.alert')).then(() => {
          this.getServerList();
        });
      });
    },
    // 获取服务实时状态
    getServerNotifyList(curr_page) {
      if (!this.showOthers) return;
      const loading = this.$refs.serverNotifyListLoading.$loading.show();

      this.$ajax.getJSON('/server/api/server_notify_list', {
        tree_node_id: this.$route.params.treeid,
        page_size: this.pageSize,
        curr_page: curr_page,
      }).then((data) => {
        loading.hide();
        this.pageNum = curr_page;
        this.total = Math.ceil(data.count/this.pageSize);
        this.serverNotifyList = data.rows;
      }).catch((err) => {
        loading.hide();
        this.$tip.error(`${this.$t('serverList.restart.failed')}: ${err.err_msg || err.message}`);
      });
    },
    // 切换服务实时状态页码
    gotoPage(num) {
      this.getServerNotifyList(num);
    },

    // 获取模版列表
    getTemplateList() {
      this.$ajax.getJSON('/server/api/template_name_list').then((data) => {
        if (this.configModal.model) {
          this.configModal.model.templates = data;
        } else {
          this.configModal.model = { templates: data };
        }
      }).catch((err) => {
        this.$tip.error(`${this.$t('serverList.restart.failed')}: ${err.err_msg || err.message}`);
      });
    },
    // 获取服务数据
    getServerConfig(id) {
      const loading = this.$loading.show({
        target: this.$refs.configFormLoading,
      });

      this.$ajax.getJSON('/server/api/server', {
        id,
      }).then((data) => {
        loading.hide();
        if (this.configModal.model) {
          this.configModal.model = Object.assign({}, this.configModal.model, data);
        } else {
          data.templates = [];
          this.configModal.model = data;
        }
      }).catch((err) => {
        loading.hide();
        this.closeConfigModal();
        this.$tip.error(`${this.$t('serverList.restart.failed')}: ${err.err_msg || err.message}`);
      });
    },
    // 编辑服务
    configServer(id) {
      this.configModal.show = true;
      this.getTemplateList();
      this.getServerConfig(id);
    },
    saveConfig() {
      if (this.$refs.configForm.validate()) {
        const loading = this.$Loading.show();
        this.$ajax.postJSON('/server/api/update_server', {
          isBak: this.configModal.model.bak_flag,
          ...this.configModal.model,
        }).then((res) => {
          loading.hide();
          this.serverList = this.serverList.map((item) => {
            if (item.id === res.id) {
              return res;
            }
            return item;
          });
          this.closeConfigModal();
          this.$tip.success(this.$t('serverList.restart.success'));
        }).catch((err) => {
          loading.hide();
          this.$tip.error(`${this.$t('serverList.restart.failed')}: ${err.message || err.err_msg}`);
        });
      }
    },
    closeConfigModal() {
      if (this.$refs.configForm) this.$refs.configForm.resetValid();
      this.configModal.show = false;
      this.configModal.model = null;
    },

    // 检查任务状态
    checkTaskStatus(taskid, isRetry) {
      return new Promise((resolve, reject) => {
        this.$ajax.getJSON('/server/api/task', {
          task_no: taskid,
        }).then((data) => {
          // 进行中，1秒后重试
          if (data.status === 1 || data.status === 0) {
            setTimeout(() => {
              resolve(this.checkTaskStatus(taskid));
            }, 3000);
          // 成功
          } else if (data.status === 2) {
            resolve(`taskid: ${data.task_no}`);
          // 失败
          }  else {
            reject(new Error(`taskid: ${data.task_no}`));
          }
        }).catch((err) => {
          // 网络问题重试1次
          if (isRetry) {
            reject(new Error(err.err_msg || err.message || this.$t('common.networkErr')));
          } else {
            setTimeout(() => {
              resolve(this.checkTaskStatus(taskid, true));
            }, 3000);
          }
        });
      });
    },
    // 添加任务
    addTask(id, command, tipObj) {
      const loading = this.$Loading.show();
      return this.$ajax.postJSON('/server/api/add_task', {
        serial: true, // 是否串行
        items: [{
          server_id: id,
          command,
        }],
      }).then((res) => {  // eslint-disable-line
        return this.checkTaskStatus(res).then((info) => {
          loading.hide();
          // 任务成功重新拉取列表
          this.getServerList();
          this.$tip.success({
            title: tipObj.success,
            message: info,
          });
        }).catch((err) => {
          throw err;
        });
      }).catch((err) => {
        loading.hide();
        // 任务失败也重新拉取列表
        this.getServerList();
        this.$tip.error({
          title: tipObj.error,
          message: err.err_msg || err.message || this.$t('common.networkErr'),
        });
      });
    },
    // 重启服务
    restartServer(id) {
      this.addTask(id, 'restart', {
        success: this.$t('serverList.restart.success'),
        error: this.$t('serverList.restart.failed'),
      });
    },
    // 停止服务
    stopServer(id) {
      this.$confirm(this.$t('serverList.stopService.msg.stopService'), this.$t('common.alert')).then(() => {
        this.addTask(id, 'stop', {
          success: this.$t('serverList.restart.success'),
          error: this.$t('serverList.restart.failed'),
        });
      });
    },
    // 下线服务
    async undeployServer({id, server_name, ...a}) {
      this.$confirm(this.$t('serverList.dlg.msg.undeploy'), this.$t('common.alert')).then(async () => {

          let {serverList, serverType} = this;
//          console.log(serverList.length, serverType, id , server_name, a);
          if (['proxy', 'router'].indexOf(serverType) > -1 && serverList.length === 1) {
            // 如果是仅有的一个 proxy、 router 节点，要确保该应用下没有模块，提醒用户删除该应用下所有的模块才可以删除router、proxy
            let hasModule = await this.$ajax.getJSON('/server/api/cache/hasModule', {serverType, serverName: server_name})
            if (hasModule) return this.$tip.warning(this.$t('pub.dlg.hasModule'));

            // 如果下线的是仅有的节点,提醒用户下线后该应用将无用
            try {
              await this.$confirm(this.$t('pub.dlg.cantUseApply'))

            } catch (err) {
              return false;
            }
          }
        try {
          await this.addTask(id, 'undeploy_tars', {
            success: this.$t('serverList.restart.success'),
            error: this.$t('serverList.restart.failed'),
          });

        } catch (err) {

        } finally {
          this.closeMoreCmdModal();
        }
      });
    },

    // 管理Servant弹窗
    manageServant(server) {
      this.servantModal.show = true;

      const loading = this.$loading.show({
        target: this.$refs.servantModalLoading,
      });

      this.$ajax.getJSON('/server/api/adapter_conf_list', {
        id: server.id,
      }).then((data) => {
        loading.hide();
        this.servantModal.model = data;
        this.servantModal.currentServer = server;
      }).catch((err) => {
        loading.hide();
        this.$tip.error(`${this.$t('serverList.restart.failed')}: ${err.err_msg || err.message}`);
      });
    },
    closeServantModal() {
      this.servantModal.show = false;
      this.servantModal.model = null;
      this.servantModal.currentServer = null;
    },
    // 新增、编辑 servant
    configServant(id) {
      // 新增
      this.servantDetailModal.model = {
        application: this.servantModal.currentServer.application,
        server_name: this.servantModal.currentServer.server_name,
        obj_name: '',
        node_name: '',
        endpoint: '',
        servant: '',
        thread_num: '',
        max_connections: '200000',
        queuecap: '10000',
        queuetimeout: '60000',
        allow_ip: '',
        protocol: 'not_tars',
        handlegroup: '',
      };
      this.servantDetailModal.isNew = true;
      // 编辑
      if (id) {
        const old = this.servantModal.model.find(item => item.id === id);
        old.obj_name = old.servant.split('.')[2];
        this.servantDetailModal.model = Object.assign({}, this.servantDetailModal.model, old);
        this.servantDetailModal.isNew = false;
      }
      this.servantDetailModal.show = true;
    },
    closeServantDetailModal() {
      if (this.$refs.servantDetailForm) this.$refs.servantDetailForm.resetValid();
      this.servantDetailModal.show = false;
      this.servantDetailModal.model = null;
    },
    // 检查绑定地址
    checkServantEndpoint(endpoint) {
      const tmp = endpoint.split(/\s-/);
      const regProtocol = /^tcp|udp$/i;
      let regHost = /^h\s(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/i;
      let regT = /^t\s([1-9]|[1-9]\d+)$/i;
      let regPort = /^p\s\d{4,5}$/i;

      let check = true;
      if (regProtocol.test(tmp[0])) {
        let flag = 0;
        for (let i = 1; i < tmp.length; i++) {  // eslint-disable-line
          // 验证 -h
          if (regHost && regHost.test(tmp[i])) {
            flag++;  // eslint-disable-line
            // 提取参数
            this.servantDetailModal.model.node_name = tmp[i].split(/\s/)[1];
            regHost = null;
          }
          // 验证 -t
          if (regT && regT.test(tmp[i])) {
            flag++;  // eslint-disable-line
            regT = null;
          }
          // 验证 -p
          if (regPort && regPort.test(tmp[i])) {
            const port = tmp[i].substring(2);
            if (!(port < 0 || port > 65535)) {
              flag++;  // eslint-disable-line
            }
            regPort = null;
          }
        }
        check = flag === 3;
      } else {
        check = false;
      }
      return check;
    },
    // 保存 servant
    saveServantDetail() {
      if (this.$refs.servantDetailForm.validate()) {
        const loading = this.$Loading.show();
        // 新建
        if (this.servantDetailModal.isNew) {
          const query = this.servantDetailModal.model;
          query.servant = [query.application, query.server_name, query.obj_name].join('.');
          this.$ajax.postJSON('/server/api/add_adapter_conf', query).then((res) => {
            loading.hide();
            this.servantModal.model.unshift(res);
            this.$tip.success(this.$t('common.success'));
            this.closeServantDetailModal();
          }).catch((err) => {
            loading.hide();
            this.$tip.error(`${this.$t('common.error')}: ${err.err_msg || err.message}`);
          });
        // 修改
        } else {
          this.servantDetailModal.model.servant=this.servantDetailModal.model.application+'.'+this.servantDetailModal.model.server_name+'.'+this.servantDetailModal.model.obj_name;
          this.$ajax.postJSON('/server/api/update_adapter_conf', this.servantDetailModal.model).then((res) => {
            loading.hide();
            this.servantModal.model = this.servantModal.model.map((item) => {
              if (item.id === res.id) {
                return res;
              }
              return item;
            });
            this.$tip.success(this.$t('common.success'));
            this.closeServantDetailModal();
          }).catch((err) => {
            loading.hide();
            this.$tip.error(`${this.$t('common.error')}: ${err.err_msg || err.message}`);
          });
        }
      }
    },
    // 删除 servant
    deleteServant(id) {
      this.$confirm(this.$t('serverList.servant.a'), this.$t('common.alert')).then(() => {
        const loading = this.$Loading.show();
        this.$ajax.getJSON('/server/api/delete_adapter_conf', {
          id,
        }).then((res) => {
          loading.hide();
          this.servantModal.model = this.servantModal.model.map((item) => {  // eslint-disable-line
            if (item.id !== id) return item;
          }).filter(item => item);
          this.$tip.success(this.$t('common.success'));
        }).catch((err) => {
          loading.hide();
          this.$tip.error(`${this.$t('common.error')}: ${err.err_msg || err.message}`);
        });
      });
    },

    // 显示更多命令
    showMoreCmd(server) {
      this.moreCmdModal.model = {
        selected: 'setloglevel',
        setloglevel: 'NONE',
        loadconfig: '',
        command: '',
        configs: null,
      };
      this.moreCmdModal.unwatch = this.$watch('moreCmdModal.model.selected', () => {
        if (this.$refs.moreCmdForm) this.$refs.moreCmdForm.resetValid();
      });
      this.moreCmdModal.show = true;
      this.moreCmdModal.currentServer = server;

      this.$ajax.getJSON('/server/api/config_file_list', {
        level: 5,
        application: server.application,
        server_name: server.server_name,
      }).then((data) => {
        if (this.moreCmdModal.model) this.moreCmdModal.model.configs = data;
      }).catch((err) => {
        this.$tip.error(`${this.$t('common.error')}: ${err.err_msg || err.message}`);
      });
    },
    sendCommand(id, command, hold) {
      const loading = this.$Loading.show();
      this.$ajax.getJSON('/server/api/send_command', {
        server_ids: id,
        command,
      }).then((res) => {
        loading.hide();
        const msg = res[0].err_msg.replace(/\n/g, '<br>');
        if (res[0].ret_code === 0) {
          const opt = {
            title: this.$t('common.success'),
            message: msg,
          };
          if (hold) opt.duration = 0;
          this.$tip.success(opt);
        } else {
          throw new Error(msg);
        }
      }).catch((err) => {
        loading.hide();
        this.$tip.error({
          title: this.$t('common.error'),
          message: err.err_msg || err.message,
        });
      });
    },
    invokeMoreCmd() {
      const model = this.moreCmdModal.model;
      const server = this.moreCmdModal.currentServer;
      // 下线服务
      if (model.selected === 'undeploy_tars') {
        this.undeployServer(server);
      // 设置日志等级
      } else if (model.selected === 'setloglevel') {
        this.sendCommand(server.id, `tars.setloglevel ${model.setloglevel}`);
      // push 日志文件
      } else if (model.selected === 'loadconfig' && this.$refs.moreCmdForm.validate()) {
        this.sendCommand(server.id, `tars.loadconfig ${model.loadconfig}`);
      // 发送自定义命令
      } else if (model.selected === 'command' && this.$refs.moreCmdForm.validate()) {
        this.sendCommand(server.id, model.command);
      // 查看服务链接
      } else if (model.selected === 'connection') {
        this.sendCommand(server.id, `tars.connection`, true);
      }
    },
    closeMoreCmdModal() {
      if (this.$refs.moreCmdForm) this.$refs.moreCmdForm.resetValid();
      if (this.moreCmdModal.unwatch) this.moreCmdModal.unwatch();
      this.moreCmdModal.show = false;
      this.moreCmdModal.model = null;
    },

    // 处理未发布时间显示
    handleNoPublishedTime(timeStr, noPubTip = this.$t('pub.dlg.unpublished')) {
      if (timeStr === '0000:00:00 00:00:00') {
        return noPubTip;
      }
      return timeStr;
    },

    openExpandModal (rowData) {
      const { server_name, node_name } = rowData;
      this.expandModal.show = true;
      this.expandModal.model.server_name = server_name;
      this.expandModal.model.node_name = node_name;
    },
    async expandService () {
      if (this.$refs.expandForm.validate()) {
        const model = Object.assign({}, this.expandModal.model);
        model.expand_nodes = this.expandModal.expandIpStr.trim().split(/[,;\n]/);
        const loading = this.$Loading.show();

        try {
          const data = await expandServerPreview(model);
          if (!data) throw new Error(this.$t('serviceExpand.form.errTips.noneNodes'));
          const previewItems = data.filter(item => item.status === this.$t('serviceExpand.form.noExpand'));
          const previewServers = [];
          const bindIps = [];
          previewItems.forEach((item) => {
            bindIps.push(item.bind_ip);
          });
          const portData = await autoPort({ node_name: bindIps.join(';') });
          portData.forEach((node, index) => {
            this.$set(previewItems[index], 'port', String(node.port || ''))
          });
          previewItems.forEach((item) => {
            previewServers.push({
              bind_ip: item.bind_ip,
              node_name: item.node_name,
              obj_name: item.obj_name,
              port: item.port,
              set: item.set,
            });
          });
          const params = {
            application: model.application,
            server_name: model.server_name,
            set: model.set,
            node_name: model.node_name,
            copy_node_config: model.copy_node_config,
            expand_preview_servers: previewServers,
          };
          const { server_conf } = await expandServer(params);
          const addTaskOption = {
            serial: false,
            items: []
          };
          let { serverType } = this;
          let group_name = "";
          if (serverType === 'router') {
            group_name = 'RouterServer'
          } else if (serverType === 'proxy') {
            group_name = 'ProxyServer'
          } else if (serverType === 'dcache') {
            group_name = 'DCacheServerGroup'
          }
          server_conf.forEach((item) => {
            addTaskOption.items.push({
              server_id: item.id.toString(),
              command: 'patch_tars',
              parameters: {
                patch_id: item.patch_version,
                bak_flag: item.bak_flag,
                update_text: '',
                group_name
              },
            })
          });
          const addTaskRsp = await addTask(addTaskOption);
          this.$tip.success(this.$t('serviceExpand.form.errTips.success'));
          this.closeExpandModal();
          this.getServerList();
          this.getServerNotifyList(1);

        } catch (err) {
          console.error(err);
          this.$tip.error(err);
        } finally {
          loading.hide();
        }

        // this.$ajax.postJSON('/server/api/expand_server_preview', model).then((data) => {
        //   if (!data) {
        //     this.$tip.error(this.$t('serviceExpand.form.errTips.noneNodes'));
        //   } else {
        //     const previewItems = data.filter(item => item.status === this.$t('serviceExpand.form.noExpand'));
        //     const previewServers = [];
        //     const bindIps = [];
        //     previewItems.forEach((item) => {
        //       bindIps.push(item.bind_ip);
        //     });
        //     this.$ajax.getJSON('/server/api/auto_port', {node_name: bindIps.join(';')}).then((portData) => {
        //       portData.forEach((node, index) => {
        //         this.$set(previewItems[index], 'port', String(node.port || ''))
        //       });
        //       previewItems.forEach((item) => {
        //         previewServers.push({
        //           bind_ip: item.bind_ip,
        //           node_name: item.node_name,
        //           obj_name: item.obj_name,
        //           port: item.port,
        //           set: item.set,
        //         });
        //       });
        //       const params = {
        //         application: model.application,
        //         server_name: model.server_name,
        //         set: model.set,
        //         node_name: model.node_name,
        //         copy_node_config: model.copy_node_config,
        //         expand_preview_servers: previewServers,
        //       };
        //       this.$ajax.postJSON('/server/api/expand_server', params).then((data) => {
        //         loading.hide();
        //         this.$tip.success(this.$t('serviceExpand.form.errTips.success'));
        //         this.closeExpandModal();
        //         this.getServerList();
        //         this.getServerNotifyList(1);
        //       }).catch((err) => {
        //         loading.hide();
        //         this.$tip.error(`${this.$t('common.error')}: ${err.message || err.err_msg}`);
        //       });
        //     }).catch((err) => {
        //       loading.hide();
        //       this.$tip.error(`${this.$t('common.error')}: ${err.message || err.err_msg}`);
        //     });
        //   }
        // }).catch((err) => {
        //   loading.hide();
        //   this.$tip.error(`${this.$t('common.error')}: ${err.message || err.err_msg}`);
        // });

      }
    },
    closeExpandModal () {
      if (this.$refs.expandForm) this.$refs.expandForm.resetValid();
      this.expandModal.show = false;
      this.expandModal.model = getInitialExpandModel();
      this.expandModal.expandIpStr = '';
    }
  },
  created() {
    this.serverData = this.$parent.getServerData();
    window.manage = this;
  },
  mounted() {
    this.getServerList();
    this.getServerNotifyList(1);
  },
};
</script>

<style lang="postcss">
@import '../../assets/css/variable.css';

.page_server_manage {
  .tbm16 {
    margin: 16px 0;
  }
  .danger {
    color: var(--off-color);
  }

  .more-cmd {
    .let-form-item__content {
      display: flex;
      align-items: center;
    }
    span.let-radio {
      margin-right: 5px;
    }
    label.let-radio {
      width: 200px;
    }
  }
}

</style>
